/*
尽可能还原 Promise 中的每一个 API, 并通过注释的方式描述思路和原理.
*/
export default class MyPromise {
    constructor(handle) {
        this['[[PromiseState]]'] = "pending"
        this['[[PromiseResult]]'] = undefined;

        //成功回调函数集合
        this.resolveFnQueue = [];
        //失败回调函数集合
        this.rejectFnQueue = [];
        try {
            handle(this._resolve, this._reject);
        } catch (e) {
            this._reject(e)
        }

    }
    _resolve = (val) => {
        // console.log(this);
        // 1.改变状态 2.修改result；
        this['[[PromiseState]]'] = "fulfilled";
        this['[[PromiseResult]]'] = val;
        // this.resolveFn(val);
        const run = () => {
            let cb; // [fn1,fn2,fn3...]
            while (cb = this.resolveFnQueue.shift()) {
                cb && cb(val);
            }

        }
        const ob = new MutationObserver(run);
        ob.observe(document.body, {
            attributes: true
        })
        document.body.setAttribute("kkb", "val");
        // setTimeout(run);
    }
    _reject(err) {
        this['[[PromiseState]]'] = "rejected";
        this['[[PromiseResult]]'] = err;
        // this.rejectFn(err);
        const run = () => {
            let cb;
            while (cb = this.rejectFnQueue.shift()) {
                cb && cb(err);
            }
        }
        // setTimeout(run);
        const ob = new MutationObserver(run);
        ob.observe(document.body, {
            attributes: true
        })
        document.body.setAttribute("kkb", "val");
    }
    then(onResolved, onRejected) {
        return new MyPromise((resolve, reject) => {
            const resolveFn = (val) => {
                try{
                    //如果有传成功的回调
                    if(onResolved) {
                        let res = onResolved && onResolved(val);
                        if (res instanceof MyPromise) {
                            res.then(resolve)
                        } else {
                            resolve(res)
                        }
                    //没有传成功的回调,解决then不传参数的情况
                    } else {
                        resolve(val)
                    }
                   

                }catch(e){
                    reject(e)
                }
            }
            //收集成功回调函数，解决多个then的调用
            this.resolveFnQueue.push(resolveFn);
            const rejectFn = (err) => {
                onRejected && onRejected(err);
                reject(err)
            }
            //收集失败回调函数
            this.rejectFnQueue.push(rejectFn);

        })
    }
    //catch方法其实就是Promise实例的then方法，第一个参数传undefined
    catch (failCallback) {
        return this.then(undefined, failCallback)
      }
    /*
        Promise.resolve的作用将现有对象为Promise对象，
        1、如果参数是一个普通的值，则返回一个新的状态为resolved的Promise对象
        2、如果参数是Promise实列，则直接返回这个Promise对象。
    */
    static resolve(value) {
        if (value instanceof MyPromise) return value;
        return new MyPromise(resolve => resolve(value));
    }
    //Promise.reject方法也会返回一个新的状态为rejected的Promise实列。
    static reject(err) {
        return new MyPromise((resolve, reject) => {
            reject(err);
        })
    }
    /*
        Promise.race()方法是将多个 Promise 实例，包装成一个新的 Promise 实例。
        新的Promise实例的值是最先改变状态的Promise的值
    */
    static race(lists) {
        return new MyPromise((reslove, reject) => {
            lists.forEach(item => {
                item.then(res => {
                    reslove(res);
                }, err => {
                    reject(err);
                })
            })
        })
    }
    /*
    Promise.all()方法接受一个数组作为参数，返回一个新的Promise实例
    */
    static all(lists) {
        return new MyPromise((reslove, reject) => {
            let resArr = [];
            let num = 0;
            lists.forEach((item, key) => {
                //Promise
                if (item instanceof MyPromise) {
                    item.then(res => {
                        resArr[key](res)
                        num++;
                        if (num >= lists.length) {
                            reslove(resArr);
                        }
                    }, reason => {
                        reject(reason)
                    })
                } else {
                    //普通值时
                    resArr[key] = item;
                    num++;
                    if (num >= lists.length) {
                        reslove(resArr);
                    }
                }
            })
        })
    }
    /*
        Promise.allSettled()方法接受一组 Promise 实例作为参数，
        包装成一个新的 Promise 实例。只有等到所有这些参数实例都返回结果，
        不管是fulfilled还是rejected，包装实例才会结束。
    */
    static allSettled(lists) {
        let resArr = new Array(lists.length);
        let num = 0
        return new MyPromise(reslove => {
            lists.forEach((item, key) => {
                let obj = {};
                item.then(res => {
                    obj['status'] = "fulfilled";
                    obj['value'] = res;
                    resArr[key] = obj;
                    num++
                    if (num >= lists.length) {
                        reslove(resArr);
                    }
                }, err => {
                    obj['status'] = "rejected";
                    obj['reson'] = err;
                    resArr[key] = obj;
                    num++
                    if (num >= lists.length) {
                        reslove(resArr);
                    }
                })
            })
        })
    }
    
    finally (callback) {
        return this.then(value => {
          return MyPromise.resolve(callback()).then(() => value);
        }, reason => {
          return MyPromise.resolve(callback()).then(() => { throw reason })
        })
      }
}